/**
 * @file STL_ThreadCheck.cpp
 * @author Derek Liu (yjkhtddx@sina.com)
 * @brief 
 * @version 2.00.05
 * @date 2021-12-12
 * 
 * @copyright Copyright Sci-Tech Laboratories (c) 2021
 * 
 */

#include "STL_ThreadCheck.h"
#include "STL_Timestamp.h"
#include "STL_Async.h"
#include <mutex>
#include <thread>

namespace STL
{
    uint64_t STL_ThreadCheck::s_thread_index = 0;
    bool STL_ThreadCheck::s_working = true;

    STL_ThreadCheck::STL_ThreadCheck() : STL_ModLog("STL_ThreadCheck")
    {
        STL_ThreadCheck::s_working = true;
        STL_ASYNC(STL_ThreadCheck::checkThread);
    }

    STL_ThreadCheck::~STL_ThreadCheck()
    {
        STL_ThreadCheck::s_working = false;
    };

    void STL_ThreadCheck::checkThread()
    {
        while (STL_ThreadCheck::s_working)
        {
            STL_ThreadCheck::getInstance()->checkTasks();
            sleep(1);
        }
    }

    std::string STL_ThreadCheck::getCheckTaskInfo(std::list<STL_ThreadCheck::ThreadCheckTask /*task*/>::iterator it)
    {
        std::string ret = "\n";
        ret += "------------------------------------------\n";
        ret += "Index       : " + std::to_string(it->index) + "\n";
        ret += "Tag         : " + it->tag + "\n";
        ret += "Timeout(ms) : " + std::to_string(it->timeout) + "\n";
        ret += "LastCheck   : " + getTimestampString("%F %T", it->lastCheck) + "\n";
        ret += "Resident    : " + (it->isResident ? std::string("true") : std::string("false")) + "\n";
        ret += "Describe    : " + it->describe + "\n";
        ret += "------------------------------------------\n";
    }

    void STL_ThreadCheck::checkTasks()
    {
        auto now = getMillTimestamp();
        {
            std::lock_guard<std::mutex> guard(m_taskListMutex);
            for (auto it = m_taskList.begin(); it != m_taskList.end();)
            {
                auto ite = it++;
                if (ite->isResident)
                { // 检车常驻进程是否阻塞
                    if (now > ite->lastCheck + ite->timeout)
                    {

                        modlog_error("%s(常驻) 执行超时 %s", ite->tag.c_str(), ite->index, ite->timeout, getCheckTaskInfo(ite).c_str());
                    }
                    ite->lastCheck = now;
                }
                else
                { // 检测临时线程是否线程超时
                    if (now > ite->lastCheck + ite->timeout)
                    {
                        modlog_error("%s(临时) 执行超时 %s", ite->tag.c_str(), ite->index, ite->timeout, getCheckTaskInfo(ite).c_str());
                        ite->lastCheck = now;
                    }
                }
            }
        }
    }

    void STL_ThreadCheck::SetCheckTaskDescribe(std::string describe)
    {
        KeepAliveCheckTask(describe);
    }

    void STL_ThreadCheck::KeepAliveCheckTask(std::string describe /* = ""*/)
    {
        auto thread_id = std::this_thread::get_id(); // 这个鬼是判断是不是同一个线程，然并卵不是一个具体的数值
        {
            std::lock_guard<std::mutex> guard(m_taskListMutex);
            for (auto it = m_taskList.begin(); it != m_taskList.end();)
            {
                auto ite = it++;
                {
                    if (ite->id == thread_id)
                    {
                        // modlog_debug("[%s]线程 保活 [index:%llu,timeout:%lld]", ite->tag.c_str(), ite->index, ite->timeout);
                        if (!describe.empty())
                        {
                            ite->describe = describe;
                        }
                        ite->lastCheck = getMillTimestamp();
                        return;
                    }
                }
            }
            modlog_error("保活失败(线程不存在)，请排查问题");
        }
    }

    void STL_ThreadCheck::AddCheckTask(std::string tag, long long msTimeout, std::string describe /* = ""*/, bool isResident /* = false*/)
    {
        STL_ThreadCheck::ThreadCheckTask task;
        task.index = ++STL_ThreadCheck::s_thread_index;
        task.id = std::this_thread::get_id(); // 这个鬼是判断是不是同一个线程，然并卵不是一个具体的数值
        task.tag = tag;
        task.timeout = msTimeout;
        task.lastCheck = getMillTimestamp();
        task.isResident = isResident;
        task.describe = describe;
        {
            std::lock_guard<std::mutex> guard(m_taskListMutex);
            for (auto it = m_taskList.begin(); it != m_taskList.end();)
            {
                auto ite = it++;
                {
                    if (ite->id == task.id)
                    {
                        modlog_error("[%s]线程 存在，请排查问题[old_tag:%s]", ite->tag.c_str(), task.tag.c_str());
                    }
                }
            }
            modlog_debug("[%s]线程 添加 [index:%llu,timeout:%lld]", task.tag.c_str(), task.tag.c_str(), task.index, task.timeout);
            m_taskList.push_back(task);
        }
    }

    void STL_ThreadCheck::DeleteCheckTask()
    {
        auto thread_id = std::this_thread::get_id(); // 这个鬼是判断是不是同一个线程，然并卵不是一个具体的数值
        {
            std::lock_guard<std::mutex> guard(m_taskListMutex);
            for (auto it = m_taskList.begin(); it != m_taskList.end();)
            {
                auto ite = it++;
                {
                    if (ite->id == thread_id)
                    {
                        modlog_debug("[%s]线程 删除 [index:%llu,timeout:%lld]", ite->tag.c_str(), ite->index, ite->timeout);
                        m_taskList.erase(ite);
                        return;
                    }
                }
            }
            modlog_error("删除失败(线程不存在)，请排查问题");
        }
    }
} // namespace STL